<template>
  <div class="case">
    <el-row class="case-row">
      <el-col :xl="6" :lg="6" :md="6" :sm="24" :xs="24">
        <el-card>
          <template #header>
            <div class="card-header">
              <span>测试用例集</span>
            </div>
          </template>
          <el-tree :data="dataSource" ref="treeRef" node-key="id" default-expand-all :expand-on-click-node="false"
            :default-checked-keys="checkedKeys" :props="defaultProps" class="tree" :highlight-current="true"
            :indent="22" @node-click="handleNodeClick" show-checkbox :check-strictly="false"
            @check-change="handleCheckChange" @check="handleCheck">
            <template #default="{ node, data }">
              <span style="display: flex; align-items: center; justify-content: left"
                :class="{ disalbed: data.isRoot }">
                <span @click.stop="handleExpand(node)">
                  <el-icon v-if="node.expanded" style="margin: 0 6px 0 2px" size="16">
                    <FolderOpened />
                  </el-icon>
                  <el-icon v-else style="margin: 0 6px 0 2px" size="16">
                    <Folder />
                  </el-icon>
                </span>
                <small>{{ node.label }}</small>
                <span v-if="data.demandNum > 0" class="num"> {{ data.demandNum }} </span>
              </span>
            </template>
          </el-tree>
        </el-card>
      </el-col>
      <el-col :xl="18" :lg="18" :md="18" :sm="24" :xs="24">
        <el-card>
          <template #header>
            <div class="card-header">
              <span>用例列表</span>
            </div>
          </template>
          <el-table v-loading="loading" :data="currentPageData" :show-overflow-tooltip="true" @select="handleSelect"
            @select-all="handleSelectAll" @selection-change="handleSelectionChange" height="350" row-key="id"
            ref="tableRef">
            <el-table-column align="center" type="selection" width="40" reserve-selection />
            <!-- <el-table-column align="center" label="suite" prop="suite" /> -->
            <el-table-column align="center" label="名称" prop="name" />
            <el-table-column align="center" label="测试类型" prop="typeName" />
            <el-table-column align="center" label="创建人" prop="creatorName" />
            <el-table-column align="center" label="创建时间" prop="createTime" />
            <el-table-column label="测试人员">
              <template #default="scope">
                <el-select v-model="scope.row.testUserId" placeholder="请选择"
                  @change="(val) => changeTestUser(val, scope.row)">
                  <el-option v-for="item in memberList" :key="item.id" :label="item.nickname" :value="item.id" />
                </el-select>
              </template>
            </el-table-column>
          </el-table>
          <!-- 分页 -->
          <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
            :current-page="currentPage" :page-sizes="[5, 10, 20, 30, 40]" :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper" :total="total" style="margin: 10px 0" />
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
defineOptions({ name: 'UseCaseCom' })
import * as TestPlanApi from '@/api/testPlan'
import { getTestboxTree, getPage } from '@/api/usecase'
import { FolderOpened, Folder, Document } from '@element-plus/icons-vue'
import { useAppStore } from '@/store/modules/app'
import { propTypes } from '@/utils/propTypes'
const appStore = useAppStore()
const projectId = computed(() => appStore.getSelectProject)
const dataSource = ref([] as any)
const loading = ref(false) // 列表的加载中
const total = ref() // 列表的总页数
const list = ref([] as any) // 列表的数据
const treeRef = ref() //tree Ref
const memberList = ref([] as any) // 成员列表
const tableRef = ref() // 列表ref
const checkedKeys = ref([] as any) // 选中树节点
let flatTreeList = []
let filterData = [] as any
const queryParams = reactive({
  // 用例列表参数
  pageNo: 1,
  pageSize: 100000000,
  projectId: projectId.value,
  suite: '',
  parent: ''
})
const currentPage = ref(1)
const pageSize = ref(5)
const selectRowObj = ref({} as any) //测试人员与用例 对应关系存储
let isEdit = false
const message = useMessage() // 消息弹窗

const defaultProps = {
  children: 'children',
  label: 'name'
}
const handleExpand = (node) => {
  if (!node.isLeaf) {
    node.expanded = !node.expanded
  }
}
// 编辑时 回显数据
const props = defineProps({
  suiteIds: propTypes.array.def([] as any),
  caseIds: propTypes.array.def([] as any),
  type: propTypes.string.def('')
})

const currentPageData = computed(() => {
  const start = (currentPage.value - 1) * pageSize.value
  const end = start + pageSize.value
  return filterData.slice(start, end)
})

// 获取树列表
const getTreeList = async () => {
  let data = await getTestboxTree({ projectId: projectId.value })
  dataSource.value = data ? [data] : []
  flatTreeList = flattenTree(data)
}
// 获取成员列表
const getMembers = async () => {
  let data = await TestPlanApi.getTestUserList({
    projectId: projectId.value
  })
  memberList.value = data
}
/**
 * 获取右侧列表
 */
const getList = async () => {
  loading.value = true
  list.value = []
  try {
    let res = await getPage(queryParams)
    if (res.records.length) {
      res.records.forEach((item) => {
        const caseSelected: any = props.caseIds.find((c) => c.caseId == item.id)
        const category: any = flatTreeList.find((f: any) => f.id == item.suite) || {}
        const obj = {
          ...item,
          selected: caseSelected ? true : false,
          category,
          testUserId: caseSelected?.testUserId,
          _setDataCheck: (item, flag) => {
            item.selected = flag
            tableRef.value.toggleRowSelection(item, flag)
          }
        }
        if (!category._dataChildren) {
          category._dataChildren = [obj]
        } else {
          category._dataChildren.push(obj)
        }
        list.value.push(obj)
      })
      total.value = res.total
      handleNodeClick(dataSource.value[0])
    }
    loading.value = false
  } finally {
    loading.value = false
  }
}
const handleSizeChange = (val) => {
  pageSize.value = val
}
const handleCurrentChange = (val) => {
  currentPage.value = val
}

// 点击节点获取表格列表
const handleNodeClick = (data) => {
  if (!data) return
  currentPage.value = 0
  // 过滤
  if (!data.children || !data.children.length) {
    filterData = list.value.filter((l) => {
      return l.suite == data.id
    })
  } else {
    filterData = collectDataFromSubtree(data, list.value)
  }
  total.value = filterData.length
  currentPage.value = 1
  nextTick(() => {
    if (isEdit) {
      const selects = list.value.filter((k) => k.selected)
      list.value.forEach((f, index) => {
        tableRef.value.toggleRowSelection(f, selects.some(s => s.id == f.id))
      })
    }
  })
}
/**
 * 从总数据中过滤 用例集父节点 下面子节点所有关联数据
 */
const collectDataFromSubtree = (node, dataList) => {
  let result = [] as any

  // 如果节点有子节点，则递归处理每个子节点
  if (node.children && node.children.length > 0) {
    for (let child of node.children) {
      const childResult = collectDataFromSubtree(child, dataList)
      for (let item of childResult) {
        result.push(item) // 直接将子结果中的每一项添加到结果数组中
      }
    }
  }

  // 对于叶子节点，查找与之关联的数据
  for (let dataItem of dataList) {
    if (dataItem.suite === node.id) {
      result.push(dataItem) // 直接将匹配的数据项添加到结果数组中
    }
  }

  return result
}
const emit = defineEmits(['nodeSuccess', 'caseSuccess', 'testUserSuccess']) // 定义 success 事件，用于操作成功后的回调
const flattenTree = (node, result = [] as any) => {
  if (!node._setChecked) {
    node._setChecked = (flag: boolean) => {
      //递归遍历子节点，直到找到有数据的节点，将数据状态更新为当前状态
      node._dataChildren &&
        node._dataChildren.forEach((n) => {
          n._setDataCheck(n, flag)
        })
      node.children.forEach((n) => {
        n._setChecked(flag)
      })
    }
    // 判断当前节点的关联数据是否全部未选中，是则取消当前节点选中状态，否则选中当前节点
    node.__setChecked = () => {
      if (node._dataChildren && node._dataChildren.every((k) => !k.selected) && node.children.every((k) => !k.selected)) {
        node.selected = false
        treeRef.value.setChecked(node.id, false, false)
      } else {
        node.selected = true
        treeRef.value.setChecked(node.id, true, false)
      }
    }
  }
  result.push(node)
  // 将当前节点添加到结果数组中
  if (node.children && Array.isArray(node.children)) {
    node.children.forEach((n) => {
      n._parent = node
    })
    node.children.forEach((child) => {
      flattenTree(child, result)
      // 递归处理子节点
    })
  }
  return result
}


/**
 * 左侧选中节点
 * 手动、代码操控均可触发
 */
const handleCheckChange = () => {
  const checkedNodes = treeRef.value.getCheckedNodes()
  emit('nodeSuccess', [...checkedNodes])
}
/**
 * 左侧树手动选中取消，联动右侧数据全选或者全取反
 * 手动点击触发
 */
const handleCheck = (node, checkObj) => {
  // 点击节点是否选中
  handleNodeClick(node)
  const flag = checkObj.checkedKeys.includes(node.id)
  node._setChecked(flag)
  cancelTip()
}

/**
 * 手动触发表格选中/取消
 * */ 
const handleSelect = async (selection, row) => {
  if (selection.some(s => s.id != row.id)) {
    cancelTip()
  }
}
/**
 * 手动触发表格全选/取消
 * */ 
const handleSelectAll = () => {
   cancelTip()
}
const cancelTip = async () => {
  // 选中数据
  const selectedData = tableRef.value.getSelectionRows()
  // 未选中的数据
  const notSelectedItems = list.value.filter(item1 => !selectedData.some(item2 => item1.id == item2.id));
  // 被取消的数据
  const cancelItems = notSelectedItems.filter(item1 => props.caseIds.some(item2 => item1.id == item2.caseId));
  if (cancelItems.length) {
    const names = cancelItems.map(c => c.name).join(',')
    try {
      // 在测试计划中已经执行的测试用例进行编辑，如去掉勾选，要进行二次确认，并提示可能会丢失执行过的状态。目前的勾选会导致执行状态丢失。
      await message.delConfirm(`${names}用例已经执行，如取消勾选，可能会导致执行过状态丢失！`)
    } catch {
      list.value.forEach((f, index) => {
        const flag = cancelItems.some(s => s.id == f.id)
        if(flag){
          f.selected = true
          tableRef.value.toggleRowSelection(f, true)
        }
      })
    }
  }
}
// 当表格选中状态变化时，判断是否更新树节点状态
const handleSelectionChange = async (selectedItems) => {
  filterData.forEach((item: any) => {
    const flag = selectedItems.some((selectedItem) => selectedItem.id == item.id)
    if (flag) {
      item.selected = true
    } else {
      item.selected = false
    }
    item.category.__setChecked()
  })
  emit('caseSuccess', selectedItems)
}

const changeTestUser = (val, row) => {
  // 存储表格测试人员选择数据-用于回显
  selectRowObj.value[row.id] = val
  emit('testUserSuccess', selectRowObj.value)
}

watch(
  () => props.suiteIds,
  () => {
    // 用例集回显
    if (props.suiteIds.length && !props.caseIds.length) {
      nextTick(() => {
        checkedKeys.value = props.suiteIds
        treeRef.value.setCheckedKeys(checkedKeys.value)
      })
    }
  },
  { deep: true, immediate: true }
)

watch(() => props.type, async (newValues) => {
  if (newValues == 'update') {
    isEdit = true
  }
  await getTreeList()
  getList()
}, { immediate: true })
/** 初始化 **/
onMounted(() => {
  getMembers()
})
</script>

<style lang="scss" scoped>
.case {
  background-color: var(--el-bg-color);
  height: 500px;
  box-sizing: border-box;

  .el-row {
    height: 100%;

    .el-card {
      height: 100%;

      .el-tree {
        height: 350px;
        overflow: auto;
      }
    }
  }
}

:deep(.el-tree .el-tree-node .el-tree-node__content) {
  display: flex;
  justify-content: left !important;
}
</style>
